package impl

import (
	"context"
	"database/sql"

	"gitee.com/ldysdy999/hostdemon/app/host"
	"github.com/infraboard/mcube/sqlbuilder"
)

func (i *impl) CreateHost(ctx context.Context, ins *host.Host) (*host.Host, error) {
	var (
		err      error
		resStmt  *sql.Stmt
		descStmt *sql.Stmt
	)
	//合法性校验
	if err := ins.Validate(); err != nil {
		return nil, err
	}
	//将数据一次性输入resource和host表，通过事务，要么都成功要么都失败

	//初始化一个事务，后面使用该事务进行提交
	tx, err := i.db.BeginTx(ctx, nil)
	if err != nil {
		return nil, err
	}

	//如果中途有异常就回滚，否则提交
	defer func() {
		//事务执行有异常
		if err != nil {
			err := tx.Rollback()
			i.log.Debug("tx rollback error , %s", err)
		} else {
			err := tx.Commit()
			i.log.Debug("tx commit error , %s", err)
		}
	}()

	resStmt, err = tx.Prepare(insertResourceSQL)
	if err != nil {
		return nil, err
	}
	//Perpare语句会占用SQL资源，不关闭会导致Perpare溢出
	defer resStmt.Close()

	_, err = resStmt.Exec(ins.Id, ins.Vendor, ins.Region, ins.Zone, ins.CreateAt, ins.ExpireAt, ins.Category, ins.Type, ins.InstanceId,
		ins.Name, ins.Description, ins.Status, ins.UpdateAt, ins.SyncAt, ins.SyncAccount, ins.PublicIP,
		ins.PrivateIP, ins.PayType, ins.ResourceHash, ins.DescribeHash,
	)

	if err != nil {
		return nil, err
	}

	descStmt, err = tx.Prepare(insertDescribeSQL)
	if err != nil {
		return nil, err
	}
	defer descStmt.Close()
	_, err = descStmt.Exec(ins.Id, ins.CPU, ins.Memory, ins.GPUAmount, ins.GPUSpec, ins.OSType, ins.OSName,
		ins.SerialNumber, ins.ImageID, ins.InternetMaxBandwidthOut,
		ins.InternetMaxBandwidthIn, ins.KeyPairName, ins.SecurityGroups,
	)

	if err != nil {
		return nil, err
	}
	return ins, nil
}

func (i *impl) QueryHost(ctx context.Context, req *host.QueryHostRequest) (*host.Set, error) {
	query := sqlbuilder.NewQuery(queryHostSQL).Order("create_at").Desc().Limit(int64(req.Offset()), uint(req.PageSize))
	//bulid查询语句
	sqlStr, args := query.BuildQuery()
	i.log.Debugf("sql: %s, args: %v", sqlStr, args)

	stmt, err := i.db.Prepare(sqlStr)
	if err != nil {
		return nil, err
	}
	defer stmt.Close()

	rows, err := stmt.Query(args...)
	if err != nil {
		return nil, err
	}

	//初始化返回对象
	set := host.NewSet()

	//迭代查询表的数据
	for rows.Next() {
		ins := host.NewDefaultHost()
		if err := rows.Scan(
			&ins.Id, &ins.Vendor, &ins.Region, &ins.Zone, &ins.CreateAt, &ins.ExpireAt,
			&ins.Category, &ins.Type, &ins.InstanceId, &ins.Name,
			&ins.Description, &ins.Status, &ins.UpdateAt, &ins.SyncAt, &ins.SyncAccount,
			&ins.PublicIP, &ins.PrivateIP, &ins.PayType, &ins.ResourceHash, &ins.DescribeHash,
			&ins.CPU, &ins.Memory, &ins.GPUAmount, &ins.GPUSpec, &ins.OSType, &ins.OSName,
			&ins.SerialNumber, &ins.ImageID, &ins.InternetMaxBandwidthOut, &ins.InternetMaxBandwidthIn,
			&ins.KeyPairName, &ins.SecurityGroups,
		); err != nil {
			return nil, err
		}
		set.Add(ins)
	}

	//count查询
	//build 一个count语句
	counStr, counAargs := query.BuildCount()
	countStmt, err := i.db.Prepare(counStr)
	if err != nil {
		return nil, err
	}
	defer countStmt.Close()
	if err := countStmt.QueryRow(counAargs...).Scan(&set.Total); err != nil {
		return nil, err
	}

	return set, nil
}

func (i *impl) DescribeHost(ctx context.Context, req *host.DescribeHostRequest) (*host.Host, error) {
	return nil, nil
}

func (i *impl) UpdateHost(ctx context.Context, req *host.UpdateHostRequest) (*host.Host, error) {
	return nil, nil
}

func (i *impl) DeleteHost(ctx context.Context, req *host.DeleteHostRequest) (*host.Host, error) {
	return nil, nil
}
